package com.tian.service.impl;

import com.tian.asyn.SystemUserMessageAsynchronous;
import com.tian.dto.coupon.UserActivityCouponPageReqDto;
import com.tian.dto.user.*;
import com.tian.entity.*;
import com.tian.enums.ResultCode;
import com.tian.enums.UserCouponStatusEnum;
import com.tian.enums.UserPointRecordTypeEnum;
import com.tian.mapper.*;
import com.tian.service.ActivityCouponService;
import com.tian.service.UserCouponService;
import com.tian.util.CommonResult;
import com.tian.util.RedisConstantPre;
import com.tian.util.UserCacheUtil;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author tianwc  公众号：java后端技术全栈、面试专栏
 * @version 1.0.0
 * 博客地址：<a href="http://woaijava.cc/">博客地址</a>
 * <p>
 * 用户领取优惠券、我的优惠券
 */
@Service("userCouponService")
public class UserCouponServiceImpl implements UserCouponService {
    @Resource
    private UserActivityCouponMapper userActivityCouponMapper;
    @Resource
    private ActivityCouponService activityCouponService;
    @Resource
    private PointsModifyRecordMapper pointsModifyRecordMapper;
    @Resource
    private CouponMapper couponMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private SystemUserMessageAsynchronous systemUserMessageAsynchronous;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public CommonResult<Boolean> receive(UserCouponAddDto userCouponAddDto) {

        User user = UserCacheUtil.getUser();

        CommonResult<ActivityCoupon> commonResult = activityCouponService.check(userCouponAddDto);
        if (commonResult.getCode() != ResultCode.SUCCESS.getCode()) {
            return CommonResult.failed(commonResult.getMessage());
        }
        ActivityCoupon activityCoupon = commonResult.getData();

        int userReceiveCount = userActivityCouponMapper.countByUserIdAndCouponId(userCouponAddDto.getUserId(), userCouponAddDto.getCouponId());

        if (userReceiveCount >= activityCoupon.getLimitPerUser()) {
            return CommonResult.failed(ResultCode.USER_COUPON_LIMITER);
        }
        int receiveCount = activityCoupon.getTotalCount() - activityCoupon.getRemainCount();
        if (receiveCount <= 0) {
            return CommonResult.failed(ResultCode.TREMAIN_COUNT_LIMITER);
        }
        redissonClient.getLock(RedisConstantPre.USER_POINT_LOCK_PRE + userCouponAddDto.getUserId()).lock();
        Coupon coupon = couponMapper.selectByPrimaryKey(activityCoupon.getCouponId());
        int needPoints = coupon.getPoints();
        if (needPoints > user.getPoints()) {
            return CommonResult.failed(ResultCode.ACTIVITY_NO_COUPON);
        }
        int point = user.getPoints() - needPoints;
        user.setPoints(point);
        userMapper.updateUser(user);

        UserActivityCoupon userActivityCoupon = new UserActivityCoupon();
        userActivityCoupon.setCouponId(userCouponAddDto.getCouponId());
        userActivityCoupon.setUserId(user.getId());
        userActivityCoupon.setStatus(UserCouponStatusEnum.UN_USE.getStatus());
        userActivityCouponMapper.insert(userActivityCoupon);

        PointsModifyRecord pointsModifyRecord = new PointsModifyRecord();
        pointsModifyRecord.setPoints(point);
        pointsModifyRecord.setCreateTime(new Date());
        pointsModifyRecord.setUserId(user.getId());
        pointsModifyRecord.setType(UserPointRecordTypeEnum.DELETE.getType());
        pointsModifyRecordMapper.insert(pointsModifyRecord);
        //第二个参数是站内信模板id，站内信模板是在项目开发期间就已经确定了，
        //所以，这里我们可以直接写站内信模板id即可
        //尊敬的userName，您已成功领取couponName优惠券，您可以在我的优惠券列表中查看并进行使用！
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("userName", user.getNickName());
        paramMap.put("couponName", coupon.getName());
        systemUserMessageAsynchronous.sendSystemUserMessageNoParamsMongoDb(user.getId(), 2, paramMap);
        return CommonResult.success(Boolean.TRUE);
    }

    @Override
    public CommonResult<UserCouponRecordListRespDto> list(UserActivityCouponPageReqDto userActivityCouponPageReqDto) {
        User user = UserCacheUtil.getUser();
        userActivityCouponPageReqDto.setUserId(user.getId());

        long count = userActivityCouponMapper.count(userActivityCouponPageReqDto);
        if (count == 0) {
            return CommonResult.success();
        }
        List<UserActivityCoupon> userCouponRecordList = userActivityCouponMapper.page(userActivityCouponPageReqDto);

        List<Integer> couponIdList = new ArrayList<>();
        for (UserActivityCoupon userActivityCoupon : userCouponRecordList) {
            couponIdList.add(userActivityCoupon.getCouponId());
        }

        List<Coupon> coupons = couponMapper.selectByIdList(couponIdList);
        Map<Integer, Coupon> couponMap = coupons.stream().collect(Collectors.toMap(Coupon::getId, Function.identity()));

        UserCouponRecordListRespDto userCouponRecordListRespDto = new UserCouponRecordListRespDto();

        userCouponRecordListRespDto.setList(UserCouponConvert.convert4Page(userCouponRecordList, couponMap));

        userCouponRecordListRespDto.setTotal(count);
        userCouponRecordListRespDto.setPage(userActivityCouponPageReqDto.getPage());
        userCouponRecordListRespDto.setPageSize(userActivityCouponPageReqDto.getPageSize());
        return CommonResult.success();
    }
}
